feat(spec,verify): prove-it-runs proof field + ratchet, binding 4 high-risk classes (ADR-0054 #1 + Phase 2)#2045
Merged
Merged
Conversation
…(ADR-0054 #1) ADR-0054 follow-up (1): the liveness ledger's `live` meant only a static consumer pointer — necessary but not sufficient, since a property can be live at every layer yet broken end-to-end. This adds the third leg: high-risk authorable properties must carry a `proof` (a dogfood test reference) that asserts the runtime outcome. - proof-registry.mts: the authoritative high-risk-class list (field types, analytics, RLS, flow nodes, form widgets) + which classes the ratchet enforces this phase. Field types and RLS are bound (matrix exists AND surface governed); analytics/flow/form are listed-but-blocked with honest reasons (their surface isn't governed yet / no proof yet — Phase 2). - check-liveness.mts: a bound `live` entry must carry a valid `proof` of its own class. Validation is STATIC (file exists + declares the `@proof: <id>` tag) so the gate stays seconds-cheap; running the proof remains the dogfood gate's job. Reverse check flags unregistered `@proof:` tags. - Ledger: field.type → field-zoo proof; permission.rowLevelSecurity.using → #1994 RLS proof. Dogfood proofs self-declare their `@proof:` tag. - Gate now also triggers on packages/dogfood/** so deleting/renaming a proof re-runs the check and the dangling reference is caught. - 15 unit + wiring tests; README documents the contract and ratchet. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XVdnfUAx85amkerym26vdx
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
📓 Docs Drift CheckThis PR changes 3 package(s): 89 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XVdnfUAx85amkerym26vdx
…f (ADR-0054 Phase 2) Phase 2 extends the prove-it-runs ratchet to the flow-node class. - verify: bootStack gains an opt-in `automation` flag that registers @objectstack/service-automation, so authored flows are pulled from the registry and POST /automation/:name/trigger runs their nodes. Without it, flow execution was unreachable through the harness (the dispatcher's automation routes resolved no service). Mirrors the existing `multiTenant`/`security` opt-ins; default off. - dogfood: a self-contained flow fixture (one object + one autolaunched flow whose update_record node stamps a record) + the flow-node proof. It authors the flow, triggers it over HTTP, and asserts both directions — the targeted record is stamped (node executed) AND a bystander is untouched (the input variable wired into the node filter, not a blanket update). Runs green end-to-end. - spec: flow-node class is now `bound` in proof-registry.mts; flow.nodes.type carries the proof; the liveness gate enforces it. Three classes now bound: field types, RLS, flow nodes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XVdnfUAx85amkerym26vdx
…0054) Unlocks the analytics binding that was previously blocked because its authorable surface wasn't governed. - Govern the `dataset` metadata type: new liveness/dataset.json classifies all 19 authorable props with file:line evidence from the analytics service consumer audit (26 live, 1 dead — measures.certified has no runtime consumer). `dataset` added to GOVERNED in check-liveness.mts. - Bind the analytics class: dataset.dimensions.dateGranularity carries the tz-bucketing proof (#1982/#2018) — the property whose org-timezone day-bucket behavior the proof asserts. proof-registry.mts flips analytics to bound. - Four high-risk classes now CI-enforced: field types, RLS, flow nodes, analytics. - README governed-types + high-risk tables updated; changeset description updated. Verified: liveness gate green (dataset 27 classified); 17 registry tests; the analytics proof runs green; full dogfood suite 59/59. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XVdnfUAx85amkerym26vdx
os-zhuang
marked this pull request as ready for review
June 19, 2026 11:00
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
ADR-0054 follow-up (1) + Phase 2: define the authoritative high-risk-class list and add the
prooffield + ratchet to the spec liveness gate, then bind the high-risk classes — including new runtime proofs/bindings for flow nodes and analytics.Until now, a
liveclassification in the liveness ledger meant only a static pointer to a consumer — proof that something reads the property. That is necessary but not sufficient: a property can be live at every layer yet broken end-to-end (the break lives in the engine↔driver↔service↔HTTP integration — #2018, therating/slider/togglefidelity leak). ADR-0054 adds the third leg — prove-it-runs: for high-risk authorable classes,livemust carry aproof(a@objectstack/dogfoodtest that authors the property against the real in-process stack and asserts the runtime outcome).The earlier ADR-0054 follow-ups are already merged: field-fidelity fix + field-zoo (#2025/#2022), tz-bucketing proof (#2018), the
@objectstack/verifyengine (#2041), and the #1994 RLS seed + multi-user harness (#2024/#2032). This adds the missing keystone (the ratchet) and binds four classes.Design (the proof contract)
proof="<repo-relative-file>#<proof-id>". The dogfood test self-declares the id with a greppable// @proof: <id>tag near its top.liveentry must carry a valid proof of its own class. The reverse check flags any@proof:tag underpackages/dogfood/test/**not registered inproof-registry.mts(warning).packages/dogfood/**, so deleting/renaming a proof re-runs the check and a dangling reference is caught.The ratchet — four classes bound (ADR §3)
A class is CI-enforced only once it has both a runtime proof and a governed ledger entry to carry it.
field.typefield-zoo-roundtrip#field-type-roundtrippermission.rowLevelSecurity.usingrls-fixture#rls-by-id-writeflow.nodes.typeflow-node#flow-node-execution(new proof)dataset.dimensions.dateGranularityanalytics-timezone#analytics-tz-bucketing(newly bound)Phase 2 — new this PR
Flow-node runtime proof. Flow execution wasn't reachable through the harness (
bootStackregistered no automation service). Mirroring how the RLS proof first needed a multi-user harness capability:@objectstack/verify:bootStackgains an opt-inautomationflag that registers@objectstack/service-automation; the app's flows are then pulled from the registry and their nodes execute. Default off — standard boot stays lean.autolaunchedflow whoseupdate_recordnode stamps a record) triggers the flow over HTTP and asserts both directions — the targeted record IS stamped (node executed) and a bystander is not (the input variable wired into the node's filter, not a blanket update).Govern
dataset+ bind analytics. The analytics proof existed (#2018) but its surface wasn't governed. This addsliveness/dataset.json(all 19 authorable props classified with file:line evidence from a consumer audit; 26 live, 1 dead) and bindsdataset.dimensions.dateGranularityto the tz-bucketing proof.Verification (all local, green)
pnpm --filter @objectstack/spec check:liveness→ green; 11 governed types; reports the 4 bound classes.livewith no proof → fail; orphan tag → warning.proof-registry.test.ts).🤖 Generated with Claude Code